package com.chatplus.application.service.file.impl;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import com.chatplus.application.common.exception.BadRequestException;
import com.chatplus.application.common.logging.SouthernQuietLogger;
import com.chatplus.application.common.logging.SouthernQuietLoggerFactory;
import com.chatplus.application.dao.file.FileDao;
import com.chatplus.application.domain.entity.file.FileEntity;
import com.chatplus.application.domain.vo.file.UpLoadFileVo;
import com.chatplus.application.enumeration.FileChannelEnum;
import com.chatplus.application.service.basedata.ConfigService;
import com.chatplus.application.service.file.FileService;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.util.UriComponentsBuilder;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.Collection;
import java.util.Date;

/**
 * @author lingyuan
 */
@Service("fileServiceLocal")
public class LocalFileServiceImpl extends FileService {

    private static final SouthernQuietLogger LOGGER = SouthernQuietLoggerFactory.getLogger(LocalFileServiceImpl.class);
    private final String contextPath;

    public LocalFileServiceImpl(FileDao fileDao
            , ConfigService configService
            , ServerProperties serverProperties) {
        super(configService, fileDao);
        this.contextPath = serverProperties.getServlet().getContextPath();
    }

    /**
     * 上传文件远程调用SDK
     */
    @Override
    public UpLoadFileVo uploadFile(MultipartFile scrFile, Long userId) {
        // 处理文件上传逻辑
        if (!scrFile.isEmpty()) {
            try {
                // 获取文件名
                String fileName = scrFile.getOriginalFilename();
                String fileSuffix = StringUtils.substring(fileName, fileName.lastIndexOf("."), fileName.length());
                String hashId;
                String contentType;
                try (InputStream inputStream = scrFile.getInputStream()) {
                    contentType = tika.detect(inputStream);
                    inputStream.reset();
                    hashId = DigestUtils.sha256Hex(inputStream);
                } catch (Exception e) {
                    LOGGER.message("文件上传失败-hash获取失败").exception(e).error();
                    throw new BadRequestException("文件上传失败-hash获取失败");
                }
                FileEntity fileEntity = getByHashId(hashId);
                // 如果已经存在相同的文件而且没有被删除，则直接返回
                if (fileEntity != null) {
                    return new UpLoadFileVo(true,
                            fileEntity.getId().toString(),
                            fileEntity.getOriginalName(),
                            fileEntity.getHashId(),
                            fileEntity.getUrl(),
                            fileEntity.getContentType(),
                            fileEntity.getFileSuffix());
                }
                // 指定文件存储路径，这里存储在当前目录下
                String filePath = getPath(fileSuffix);
                // 将文件保存到指定路径
                scrFile.transferTo(new File(filePath));

                fileEntity = new FileEntity();
                fileEntity.setContentType(scrFile.getContentType());
                String url;
                String fileUrl = getFileConfig().getAccessBaseUrl();
                UriComponentsBuilder builder = UriComponentsBuilder.fromUri(URI.create(fileUrl)).replaceQuery("");
                if (contentType.startsWith("image")) {
                    url = builder.replacePath(contextPath + "/api/image/{hashId}").build(hashId).toString();
                } else {
                    url = builder.replacePath(contextPath + "/api/file/{hashId}").build(hashId).toString();
                }
                fileEntity.setUrl(url);
                fileEntity.setUserId(userId);
                fileEntity.setHashId(hashId);
                fileEntity.setFilePath(filePath);
                fileEntity.setOriginalName(fileName);
                fileEntity.setContentType(contentType);
                fileEntity.setFileSuffix(fileSuffix);
                fileEntity.setService(getUploadChannel().getValue());
                fileDao.insert(fileEntity);
                return new UpLoadFileVo(true,
                        fileEntity.getId().toString(),
                        fileEntity.getOriginalName(),
                        fileEntity.getHashId(),
                        fileEntity.getUrl(),
                        fileEntity.getContentType(),
                        fileEntity.getFileSuffix());
            } catch (IOException e) {
                LOGGER.message("文件上传失败").exception(e).error();
                return new UpLoadFileVo(false);
            }
        } else {
            return new UpLoadFileVo(false);
        }
    }

    @Override
    public InputStream getInputStream(Long id) {
        FileEntity fileEntity = fileDao.selectById(id);
        if (fileEntity != null) {
            try {
                return new FileInputStream(fileEntity.getFilePath());
            } catch (IOException e) {
                LOGGER.message("文件获取失败").exception(e).error();
            }
        }
        return null;
    }

    @Override
    public FileChannelEnum getUploadChannel() {
        return FileChannelEnum.LOCAL;
    }

    @Override
    public void deleteByIds(Collection<Long> ids) {

    }

    @Override
    public void download(Long ossId, String fileName, HttpServletResponse response) {

    }

    public String getPath(String suffix) {
        // 生成uuid
        String uuid = IdUtil.fastSimpleUUID();
        // 文件路径
        String path = getFileConfig().getLocalPath() + FILE_SEPARATOR + DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN);
        // 判断文件夹是否存在，不存在则创建文件夹
        File file = new File(path);
        if (!file.exists()) {
            boolean wasSuccessful = file.mkdirs();
            if (!wasSuccessful) {
                LOGGER.message("文件夹创建失败").context("path", path).error();
                throw new BadRequestException("文件夹创建失败");
            }
        }
        return path + FILE_SEPARATOR + uuid + suffix;
    }
}
